#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
#include <QDebug>
#include <QTimer>
#include <QDateTime>
#include <QFile>
#include <QFileInfo>
#include <QPropertyAnimation>
#include <QKeyEvent>
#include <QVBoxLayout>
#include <QRadioButton>
#include <QPointer>
#include <QDialog>
#include <QJsonDocument>
#include <QJsonObject>
#include <QHttpMultiPart>
#include "marqueewidget.h"
#include <QThread>
#include "game.h"
#include "questionsyncer.h"
#include "videodownloader.h"

#define ENABLE_GPIO_KEY 1

game *gameUI = nullptr;

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->resize(QSize(2256,1504));
    process = new QProcess(this);
    serialPort = new QSerialPort(this);
    serialPort->setPortName("ttyS3");
    serialPort->setBaudRate(115200);
    serialPort->setStopBits(QSerialPort::StopBits::OneStop);
    serialPort->setDataBits(QSerialPort::DataBits::Data8);
    serialPort->setParity(QSerialPort::NoParity);
    serialPort->setFlowControl(QSerialPort::NoFlowControl);
    //打开串口
    if(!serialPort->open(QIODevice::ReadWrite))
    {
        QMessageBox::about(this,"错误","串口打开失败");
        return;
    }
    //每当串口收到新数据时，就自动执行 readData() 函数来处理这些数据
    connect(serialPort,SIGNAL(readyRead()),this,SLOT(readData()));

    //播放器设置
    pPlayer = new QMediaPlayer(this);
    //自定义播放类
    my_player = new myPalyer(this);
    connect(my_player,&myPalyer::thumbnailGenerated,this,&Widget::updateVideoIcon);
    my_player->getFilesInDirectory("./videos");

#if ENABLE_GPIO_KEY
    keyTimer = new QTimer(this);
    // 连接定时器超时信号到检测函数
    connect(keyTimer, &QTimer::timeout, this, &Widget::checkKeys);
    // 每隔 200ms 检测一次按键
    keyTimer->start(200);

    debounceTimer = new QTimer(this);
    // 消抖定时器：单次触发，延迟 10ms
    debounceTimer->setSingleShot(true);
    connect(debounceTimer, &QTimer::timeout, this, &Widget::debounceCheck);
#endif
    // 初始化自定义时间为当前系统时间
    m_customTime = QDateTime::currentDateTime();
    timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, &Widget::updateTimeDisplay);
    timer->start(1000); // 每秒触发一次
    //初始化备忘录定时器
    reminderTimer = new QTimer(this);
    connect(reminderTimer, &QTimer::timeout, this, &Widget::checkReminders);
    reminderTimer->start(60 * 1000 * 10);  // 60秒间隔

    QFile file(":/ui.qss");//换为自己的路径
    //判断文件是否存在
    if(file.exists())
    {
        //以只读方式打开
        file.open(QFile::ReadOnly);
        //以字符串方式保存读出的结果
        QString styleSheet = QLatin1String(file.readAll());
        //设置全局样式
        qApp->setStyleSheet(styleSheet);
        //关闭文件
        file.close();
    }
    //根据数据库类型来连接数据
    db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName("./database/memoryGame.db");

    //打开数据库
    if(!db.open())
    {
        qDebug() << "open error" << db.lastError();
        return;
    }
    MarqueeWidget *marquee = new MarqueeWidget(ui->frame_12); // 将 frame 作为父控件
    marquee->setGeometry(ui->frame_12->rect()); // 设置为 frame 的大小
    marquee->setTexts({
        "出门记得带上工牌，带上手机！",
        "每天都要多喝水，保持健康噢！",
        "晨光已爬上窗台，像您年轻时的笑颜",
        "每次做完菜要记得关火噢"
    });

    // 初始化GStreamer进程
    //gstProcess = new QProcess(this);
    videoProcess = new QProcess(this);  // 初始化
    audioProcess = new QProcess(this);


    networkManager = new QNetworkAccessManager(this);
    // 初始化定时器
    uploadTimer = new QTimer(this);
    pollTimer = new QTimer(this);

    // 每秒上传传感器数据
    connect(uploadTimer, &QTimer::timeout, this, &Widget::uploadSensorData);
    uploadTimer->start(3000);

    // 每秒轮询控制指令
    connect(pollTimer, &QTimer::timeout, this, &Widget::pollControlCommands);
    pollTimer->start(1000);

    reminderSync = new SyncWorker(this);

    //题目同步
#if 1
    QuestionSyncer syncer;
    syncer.startSyncQuestion(10);
#endif
#if 0
    //云端视频同步
    VideoDownloader downloader;
    downloader.fetchVideos();
    downloader.start();
#endif

    QProcess *process = new QProcess(this);
    process->start("./getNetVideos");

    //阴影设置
    ui->frame->setGraphicsEffect(shadowBackSet());
    ui->frame_10->setGraphicsEffect(shadowBackSet());
    ui->enviroment->setGraphicsEffect(shadowBackSet());
    ui->frame_2->setGraphicsEffect(shadowBackSet());
    ui->game->setGraphicsEffect(shadowBackSet());
    ui->RFID->setGraphicsEffect(shadowBackSet());
    ui->pushButton_2->setGraphicsEffect(shadowBackSet());
    ui->pushButton_3->setGraphicsEffect(shadowBackSet());
    ui->pushButton->setGraphicsEffect(shadowBackSet());
    ui->wendu->setGraphicsEffect(shadowBackSet());
    ui->radar->setGraphicsEffect(shadowBackSet());
    ui->air->setGraphicsEffect(shadowBackSet());
    ui->humidifier->setGraphicsEffect(shadowBackSet());
    ui->frame_13->setGraphicsEffect(shadowBackSet());
    ui->pushButton_12->setGraphicsEffect(shadowBackSet());
    ui->pushButton_11->setGraphicsEffect(shadowBackSet());
    ui->ergency->setGraphicsEffect(shadowBackSet());
    ui->pushButton_15->setGraphicsEffect(shadowBackSet());

    ui->pushButton_4->setGraphicsEffect(createShadowEffect());
    ui->pushButton_5->setGraphicsEffect(createShadowEffect());
    ui->pushButton_6->setGraphicsEffect(createShadowEffect());
    ui->pushButton_7->setGraphicsEffect(createShadowEffect());
    ui->pushButton_8->setGraphicsEffect(createShadowEffect());
    ui->pushButton_9->setGraphicsEffect(createShadowEffect());
    ui->nextPage->setGraphicsEffect(createShadowEffect());
    ui->prevPage->setGraphicsEffect(createShadowEffect());

    //页面设置
    m_stackedLayout = new QStackedLayout(this);
    m_stackedLayout->addWidget(ui->widget_3);
    gameUI = new game(this,serialPort,this);
    m_stackedLayout->addWidget(gameUI->getGameWidget());
    gameUI->dateInit(&m_customTime);
    m_stackedLayout->addWidget(ui->PlayUI);
    m_stackedLayout->addWidget(ui->shoot);

    Widget::getTodoList();
    Widget::checkReminders();
}

Widget::~Widget()
{
    delete ui;
    delete serialPort;
    delete timer;
    delete keyTimer;
    delete debounceTimer;
    delete foucs;
    delete m_stackedLayout;
    delete gameUI;
}

void Widget::readData()
{
    QByteArray arr = serialPort->readAll();
    // 检查数据是否为空
    if (arr.isEmpty()) {
        return;
    }

   // 确保至少有一个字节（防止越界访问）
    if (arr.size() < 1) {
        return;
    }
    // 获取首字节作为标识符
    char header = arr[0];
    // 提取后续数据（从索引1开始）
    QByteArray data = arr.mid(1);
    //qDebug() << data << endl;

    if(header == 'A')//天气预报温度
    {
        ui->broadcastTemp->setText(QString::fromUtf8(data)); // 转换为QString
    }
    else if(header == 'G')//天气预报湿度
    {
        ui->broadcastHumi->setText(QString::fromUtf8(data));
    }
    else if(header == 'H')//室内湿度，温度
    {
        quint8 value = static_cast<quint8>(data.at(0));
        ui->label_4->setText(QString::number(value));
        value = static_cast<quint8>(data.at(1));
        ui->label_14->setText(QString::number(value));
    }
    else if(header == 'B')//天气
    {
        QString weather = QString::fromUtf8(data);
        ui->label_3->setText(weather);
        if (weather == "晴")
        {
            ui->tianqi_icon->setStyleSheet(
                        "border-image: url(:/icons/sun.png);");
        }
        else if (weather == "小雨" || weather == "中雨" || weather == "大雨")
        {
            ui->tianqi_icon->setStyleSheet(
                        "border-image: url(:/icons/rain.png);");
        }
        else if (weather == "阴")
        {
            ui->tianqi_icon->setStyleSheet(
                        "border-image: url(:/icons/overcast.png);");
        }
        else if (weather == "多云")
        {
            ui->tianqi_icon->setStyleSheet(
                        "border-image: url(:/icons/tianqi.png);");
        }
    }
    else if(header == 'C')//时间
    {
        QString strTime = QString::fromUtf8(data);
        QDateTime customTime = QDateTime::fromString(strTime, "yyyy-MM-dd HH:mm:ss");
        if (customTime.isValid()) {
            //  更新自定义时间
            m_customTime = customTime;
            gameUI->dateInit(&m_customTime);
            //  立即更新 UI
            ui->label_5->setText(m_customTime.toString("yyyy-MM-dd HH:mm:ss"));
        } else {
            qDebug() << "解析失败，请检查格式是否正确";
        }
    }
    else if(header == 'D')//雷达
    {
        quint8 value = static_cast<quint8>(data.at(1));
        //value = value * 2 / 3;
        if(value >= 80)
        {
            sendManualAlarm("患者运动幅度过大，跌倒警告！");
        }
        ui->label_19->setText(QString::number(value));//体动特征
        value = static_cast<quint8>(data.at(4));
        //value = value * 2 / 3;
        ui->label_20->setText(QString::number(value));
        value = static_cast<quint8>(data.at(2));
        //value = value * 2 / 3;
        ui->label_32->setText(QString::number(value));
        value = static_cast<quint8>(data.at(0));
        if(value == 0)
        {
            ui->label_38->setText("无人");
        }
        else
        {
            ui->label_38->setText("有人");
        }
    }
    else if(header == 'E')//烟雾
    {
        ui->label_23->setText(QString::fromUtf8(data)); // 转换为QString
    }
    else if(header == 'F')//RFID
    {
        quint8 value = static_cast<quint8>(data.at(0));//获取得到的是哪个标签
        if(value == 0x01)
        {
            ui->IDCard_Text->setText("已携带");
            carried[0] = 1;
        }
        else if (value == 0x02)
        {
            ui->Bottle_Text->setText("已携带");
            carried[1] = 1;
        }
        else if (value == 0x03)
        {
            ui->Pocket_Text->setText("已携带");
            carried[2] = 1;
        }
        else if(value == 0xBB)
        {
            // 使用lambda捕获this和carried数组（需确保生命周期）
            auto sendUncarried = [this]() {
                if (this->carried[0] == 0) {
                    ui->IDCard_Text->setText("未携带");
                    serialPort->write("uncarried1");
                }
                QTimer::singleShot(1000, [this]() {
                    if (this->carried[1] == 0) {
                        ui->Bottle_Text->setText("未携带");
                        serialPort->write("uncarried2");
                    }
                    QTimer::singleShot(1000, [this]() {
                        if (this->carried[2] == 0) {
                            ui->Pocket_Text->setText("未携带");
                            serialPort->write("uncarried3");
                        }
                    });
                });
            };

            sendUncarried(); // 启动链式调用
            QTimer::singleShot(10000, this, [this]() {
                ui->IDCard_Text->setText("");
                ui->Bottle_Text->setText("");
                ui->Pocket_Text->setText("");
            });
        }
    }
    else if(header == 'Z')//界面切换
    {
        if(data == "home")
        {
            m_stackedLayout->setCurrentIndex(0);
            if(m_stackedLayout->currentIndex() == 1)//如果在训练界面，没有说结束训练或情景模拟直接喊回到主界面
            {
                gameUI->buttonClick();
                gameUI->SenceCliked();
            }
        }
        else if(data == "train")
        {
            m_stackedLayout->setCurrentIndex(1);
        }
        else if(data == "start" || data == "end")
        {
            if(m_stackedLayout->currentIndex() == 1)//确保只在训练界面触发
            {
                gameUI->buttonClick();
            }
        }
        else if(data == "vedio")
        {
            if(m_stackedLayout->currentIndex() == 0)//确保只在主界面触发
            {
                ui->pushButton->animateClick();
            }
        }
        else if(data == "senceStart" || data == "senceEnd")
        {
            if(m_stackedLayout->currentIndex() == 1)//确保只在训练界面触发
            {
                gameUI->SenceCliked();
            }
        }
        else if(data == "daily")
        {
            if(m_stackedLayout->currentIndex() == 1)//确保只在训练界面触发
            {
                gameUI->dailyClick();
            }
        }
        else if(data == "meat")
        {
            if(m_stackedLayout->currentIndex() == 1)//确保只在训练界面触发
            {
                gameUI->meatClick();
            }
        }
        else if(data == "fruilt")
        {
            if(m_stackedLayout->currentIndex() == 1)//确保只在训练界面触发
            {
                gameUI->fruiltClick();
            }
        }
        else if(data == "pack")
        {
            if(m_stackedLayout->currentIndex() == 1)//确保只在训练界面触发
            {
                gameUI->packClick();
            }
        }
        else if(data == "exit")
        {
            if(m_stackedLayout->currentIndex() == 1)//确保只在训练界面触发
            {
                gameUI->exitButtonClick();
            }
        }
    }
    else if(header == 'Y')//语音控制
    {
        if(data == "humidifier")
        {
            ui->pushButton_3->animateClick();
        }
        if(data == "light")
        {
            ui->pushButton_13->animateClick();
        }
    }
    else if(header == 'X')//语音控制
    {
        if(m_stackedLayout->currentIndex() == 2)//确保只在播放界面触发
        {
            if(data.startsWith("video"))
            {
                QList<QPushButton *> button = {
                    ui->pushButton_4,ui->pushButton_5,ui->pushButton_6,
                    ui->pushButton_7,ui->pushButton_8,ui->pushButton_9
                };
                QString suffix = data.mid(5);
                uint8_t num = suffix.toUInt();
                qDebug() << num << endl;
                button[num - 1]->animateClick();
            }
        }

        else if(data == "record")
        {
            if(m_stackedLayout->currentIndex() == 0)
            {
                serialPort->write("startRecord");
                QTimer::singleShot(4000, this, [this]() {
                    ui->pushButton_12->animateClick();
                });
            }
        }
    }

    else
    {
        serialBuffer.append(arr); // 将数据追加到共享缓冲区
        emit newDataAvailable();   // 发出数据更新信号
    }
}

// 槽函数,更新时间
void Widget::updateTimeDisplay()
{
    // 每秒更新一次自定义时间
        m_customTime = m_customTime.addSecs(1);

        // 显示在 label 上
        ui->label_5->setText(m_customTime.toString("yyyy-MM-dd HH:mm:ss"));
}

//检查数据库是否有到时的项
void Widget::checkReminders()
{
    QSqlQuery query;
    QString sqlSelect = QString("SELECT * FROM Reminder "
                                "WHERE triggerTime <= datetime('now', 'localtime')"
                                "  AND isCompleted = 0"
                                "  AND (repeat IS NULL OR repeat != 'completed');");

    //同步云端数据库
    reminderSync->startSync();
    this->getTodoList();

    if(!query.exec(sqlSelect))
    {
        qDebug() << "checkReminders" << query.lastError();
    }
    else
    {
        int i = 0;
        int count = 0;
        QList<QLabel *> urgency = {
            ui->urgency1,ui->urgency2,ui->urgency3,
            ui->urgency4,ui->urgency5,ui->urgency6
        };
        while(query.next())
        {
            for(i = 0;i < 6;i++)
            {
                if(todoListId[i] == query.value("id").toInt())
                    break;
            }
            urgency[i]->setText("已到时");
            count++;
        }
        if(count > 0)
        {
            QString message = QString("todo%1").arg(count);
            QByteArray data = message.toUtf8();
            serialPort->write(data);
        }
    }
}

//视频播放器
void Widget::on_pushButton_clicked()
{
    showPageIcon(0);//显示第1页
    m_stackedLayout->setCurrentIndex(2);
}

//阴影设置(白色背景)
QGraphicsDropShadowEffect *Widget::shadowBackSet()
{
    //设置阴影特效
    //创建特效对象
    QGraphicsDropShadowEffect *shadow_effect = new QGraphicsDropShadowEffect(this);
    //设置偏移量，x轴，y轴
    shadow_effect->setOffset(2, 2);
    //设置阴影颜色和透明度
    shadow_effect->setColor(QColor(125, 125, 125, 200));
    //设置阴影外射的尺寸
    shadow_effect->setBlurRadius(10);

    return shadow_effect;
}

//阴影设置（深色背景）
QGraphicsDropShadowEffect *Widget::createShadowEffect()
{
    QGraphicsDropShadowEffect* shadow = new QGraphicsDropShadowEffect;

    shadow->setBlurRadius(30);     // 极致模糊
    shadow->setOffset(0, 8);       // 更夸张的偏移
    shadow->setColor(QColor(0, 0, 0, 160)); // 几乎半透明黑

    return shadow;

}

void Widget::keyPressEvent(QKeyEvent *event)
{
    if (event->key() == Qt::Key_Down) {
            focusNextPrevChild(true); // 自动切换到下一个控件
        }
    else if (event->key() == Qt::Key_Up) {
            focusNextPrevChild(false); // 自动切换到上一个控件
        }
    else if(event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return)
    {
        qDebug() << "key enter" << endl;
        this->foucs = QApplication::focusWidget();
        if(this->foucs)
        {
            qDebug() << this->foucs->objectName() << endl;
            if (QPushButton *button = qobject_cast<QPushButton*>(this->foucs))
            {
                button->animateClick(); // 视觉反馈 + 触发 click()
            }
            else if(QCheckBox *checkbox = qobject_cast<QCheckBox*>(this->foucs))
            {
                checkbox->animateClick();
            }
            else if(QRadioButton *checkbox = qobject_cast<QRadioButton*>(this->foucs))
            {
                checkbox->animateClick();
            }
        }
    }
    else {
            QWidget::keyPressEvent(event); // 其他按键交给基类处理
    }
}

//获取未完成的项
void Widget::getTodoList()
{
    QSqlQuery query;
    QString sqlGet = QString("SELECT * FROM Reminder WHERE isCompleted = 0;");
    QList<QCheckBox *> reminders = {
      ui->reminder1,ui->reminder2,ui->reminder3,
      ui->reminder4,ui->reminder5,ui->reminder6
    };
    int i = 0;

    if(!query.exec(sqlGet))
    {
        qDebug() << "get todoList error" << db.lastError();
    }
    else
    {
        while(query.next())//转到下一条
        {
            QString content = query.value("content").toString();
            int id = query.value("id").toInt();
            reminders[i]->setText(content);
            todoListId[i] = id;
            i++;
        }
    }
}

//切换到游戏界面
void Widget::on_pushButton_2_clicked()
{
    m_stackedLayout->setCurrentIndex(1);
}


void Widget::on_reminder1_clicked()
{
    if(ui->reminder1->text() != NULL)
    {
        QSqlQuery query;
        if(ui->reminder1->isChecked())
        {
            QString sqlUpdate = QString("update Reminder set isCompleted = 1 where id = %1").arg(todoListId[0]);
            if(!query.exec(sqlUpdate))
            {
                qDebug() << "update todoList error" << db.lastError();
            }
            if(ui->urgency1->text() != NULL)
            {
                ui->urgency1->setText("");
            }
        }
        else
        {
            QString sqlUpdate = QString("update Reminder set isCompleted = 0 where id = %1").arg(todoListId[0]);
            if(!query.exec(sqlUpdate))
            {
                qDebug() << "update todoList error" << db.lastError();
            }
        }
    }
}

void Widget::on_reminder2_clicked()
{
    if(ui->reminder2->text() != NULL)
    {
        QSqlQuery query;
        if(ui->reminder2->isChecked())
        {
            QString sqlUpdate = QString("update Reminder set isCompleted = 1 where id = %1").arg(todoListId[1]);
            if(!query.exec(sqlUpdate))
            {
                qDebug() << "update todoList error" << db.lastError();
            }
            if(ui->urgency2->text() != NULL)
            {
                ui->urgency2->setText("");
            }
        }
        else
        {
            QString sqlUpdate = QString("update Reminder set isCompleted = 0 where id = %1").arg(todoListId[1]);
            if(!query.exec(sqlUpdate))
            {
                qDebug() << "update todoList error" << db.lastError();
            }
        }
    }
}

void Widget::on_reminder3_clicked()
{
    if(ui->reminder3->text() != NULL)
    {
        QSqlQuery query;
        if(ui->reminder3->isChecked())
        {
            QString sqlUpdate = QString("update Reminder set isCompleted = 1 where id = %1").arg(todoListId[2]);
            if(!query.exec(sqlUpdate))
            {
                qDebug() << "update todoList error" << db.lastError();
            }
            if(ui->urgency3->text() != NULL)
            {
                ui->urgency3->setText("");
            }
        }
        else
        {
            QString sqlUpdate = QString("update Reminder set isCompleted = 0 where id = %1").arg(todoListId[2]);
            if(!query.exec(sqlUpdate))
            {
                qDebug() << "update todoList error" << db.lastError();
            }
        }
    }
}

void Widget::on_reminder4_clicked()
{
    if(ui->reminder4->text() != NULL)
    {
        QSqlQuery query;
        if(ui->reminder4->isChecked())
        {
            QString sqlUpdate = QString("update Reminder set isCompleted = 1 where id = %1").arg(todoListId[3]);
            if(!query.exec(sqlUpdate))
            {
                qDebug() << "update todoList error" << db.lastError();
            }
            if(ui->urgency4->text() != NULL)
            {
                ui->urgency4->setText("");
            }
        }
        else
        {
            QString sqlUpdate = QString("update Reminder set isCompleted = 0 where id = %1").arg(todoListId[3]);
            if(!query.exec(sqlUpdate))
            {
                qDebug() << "update todoList error" << db.lastError();
            }
        }
    }
}

void Widget::on_reminder5_clicked()
{
    if(ui->reminder5->text() != NULL)
    {
        QSqlQuery query;
        if(ui->reminder5->isChecked())
        {
            QString sqlUpdate = QString("update Reminder set isCompleted = 1 where id = %1").arg(todoListId[4]);
            if(!query.exec(sqlUpdate))
            {
                qDebug() << "update todoList error" << db.lastError();
            }
            if(ui->urgency5->text() != NULL)
            {
                ui->urgency5->setText("");
            }
        }
        else
        {
            QString sqlUpdate = QString("update Reminder set isCompleted = 0 where id = %1").arg(todoListId[4]);
            if(!query.exec(sqlUpdate))
            {
                qDebug() << "update todoList error" << db.lastError();
            }
        }
    }
}

void Widget::on_reminder6_clicked()
{
    if(ui->reminder6->text() != NULL)
    {
        QSqlQuery query;
        if(ui->reminder6->isChecked())
        {
            QString sqlUpdate = QString("update Reminder set isCompleted = 1 where id = %1").arg(todoListId[5]);
            if(!query.exec(sqlUpdate))
            {
                qDebug() << "update todoList error" << db.lastError();
            }
            if(ui->urgency6->text() != NULL)
            {
                ui->urgency6->setText("");
            }
        }
        else
        {
            QString sqlUpdate = QString("update Reminder set isCompleted = 0 where id = %1").arg(todoListId[5]);
            if(!query.exec(sqlUpdate))
            {
                qDebug() << "update todoList error" << db.lastError();
            }
        }
    }
}

#if ENABLE_GPIO_KEY
void Widget::checkKeys()
{
    QList<uint8_t> pinsToCheck = {115, 107, 108}; // 检测的按键引脚,分别对应GPIO0_B7,GPIO3_B0,GPIO3_C2
        QList<uint8_t> pressed = gpio.KeyValGet(pinsToCheck);

        if (!pressed.isEmpty()) {
            pendingKeys = pressed;  // 记录可能按下的按键
            debounceTimer->start(10); // 启动消抖定时器
        }
}

void Widget::debounceCheck()
{
    QList<uint8_t> confirmed = gpio.KeyValGet(pendingKeys);

    if (!confirmed.isEmpty()) {
        qDebug() << "Confirmed keys pressed:" << confirmed;

        for (uint8_t pin : confirmed) {
            if (pin == 115) {
                qDebug() << "Button 15 pressed!" << endl;
                focusNextPrevChild(true); // 自动切换到下一个控件
            }
            if (pin == 107) {
                qDebug() << "Button 104 pressed!" << endl;
                focusNextPrevChild(false); // 自动切换到上一个控件
            }
            if (pin == 108) {
                qDebug() << "Button 114 pressed!" << endl;
                qDebug() << "key enter" << endl;
                this->foucs = QApplication::focusWidget();
                if(this->foucs)
                {
                    qDebug() << this->foucs->objectName() << endl;
                    if (QPushButton *button = qobject_cast<QPushButton*>(this->foucs))
                    {
                        button->animateClick(); // 视觉反馈 + 触发 click()
                    }
                    else if(QCheckBox *checkbox = qobject_cast<QCheckBox*>(this->foucs))
                    {
                        checkbox->animateClick();
                    }
                    else if(QRadioButton *checkbox = qobject_cast<QRadioButton*>(this->foucs))
                    {
                        checkbox->animateClick();
                    }
                }
            }
        }
    }

    pendingKeys.clear(); // 清空待确认按键
}
#endif

void Widget::mergeAudioVideo()
{
    if (!QFile::exists(videoFile) || !QFile::exists(audioFile)) {
        QMessageBox::warning(this, "警告", "音视频文件缺失，无法合并");
        return;
    }
    QString outputFile = QString("./videos/output_%1.mp4").arg(QDateTime::currentDateTime().toString("yyyyMMdd_HHmmss"));
    // 构建 FFmpeg 命令
    QStringList ffmpegArgs;
    ffmpegArgs << "-i" << videoFile << "-i" << audioFile
               << "-c:v" << "copy" << "-c:a" << "aac" << "-b:a" << "128k"
               << "-map" << "0:v" << "-map" << "1:a" << outputFile;

    QProcess ffmpegProcess;
    ffmpegProcess.start("ffmpeg", ffmpegArgs);
    if (!ffmpegProcess.waitForStarted()) {
        QMessageBox::critical(this, "错误", "FFmpeg 启动失败");
        return;
    }
    ffmpegProcess.waitForFinished(-1);

    // 清理临时文件
    QFile::remove(videoFile);
    QFile::remove(audioFile);

    if (QFile::exists(outputFile)) {
        //QMessageBox::information(this, "完成", "录制已完成，输出文件: " + outputFile);
        m_stackedLayout->setCurrentIndex(0);
        this->resize(QSize(2256,1504));
        my_player->getFilesInDirectory("./videos");
        uploadVideo(outputFile);
    }
    else {
        QMessageBox::critical(this, "错误", "合并失败，请检查 FFmpeg 日志");
    }
}

void Widget::showPageIcon(uint8_t nowPageIndex)
{
    QList<QLabel *>label = {
        ui->video1,ui->video2,ui->video3,
        ui->video4,ui->video5,ui->video6
    };
    QList<QFrame *>frame = {
        ui->frame_14,ui->frame_16,ui->frame_17,
        ui->frame_18,ui->frame_19,ui->frame_20,
    };
    uint8_t i = 0;
    QString showPage = "第%1页";
    ui->label_35->setText(showPage.arg(nowPageIndex + 1));
    //每次进入界面清空上一次显示
    for(i = 0;i < 6;i++)
    {
        label[i]->setPixmap(QPixmap());
        frame[i]->setStyleSheet("border-radius: 20px;");
        this->videoPath[i] = "";
    }
    for(i = 0;i < countValidDataInRow(nowPageIndex);i++)
    {
        if (QFile::exists(thumbnailTable[nowPageIndex][i])) {
            QPixmap pixmap(thumbnailTable[nowPageIndex][i]);
            if (!pixmap.isNull()) {
                label[i]->setPixmap(pixmap.scaled(label[i]->size(), Qt::IgnoreAspectRatio));
                frame[i]->setStyleSheet("border-radius: 20px;"
                                        "border-image: url(:/icons/play.png);");
                this->videoPath[i] = videoTable[nowPageIndex][i];
            } else {
                label[i]->setText("invalid image");
            }
        } else {
            label[i]->setText("file not exist");
        }
    }
}

int Widget::countValidDataInRow(int row) const
{
    if (row < 0 || row >= videoTable.size()) {
        return 0;  // 行索引无效，返回0
    }

    int count = 0;
    const QVector<QString>& cells = videoTable[row];
    for (const QString& cell : cells) {
        if (!cell.isEmpty()) {
            ++count;
        }
    }

    return count;
}

void Widget::updateDeviceStatus(const QString &field, const QString &value)
{
    QJsonObject payload;
    payload[field] = value;
    QNetworkRequest request;
    request.setUrl(QUrl("http://47.109.75.129:3000/api/device/status"));
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
    QNetworkReply *reply = networkManager->post(request, QJsonDocument(payload).toJson());
    connect(reply, &QNetworkReply::finished, this, [this, reply]() {
            if (reply->error() == QNetworkReply::NoError) {
                qDebug() << "设备状态更新成功";
            } else {
                qDebug() << "设备状态更新失败:" << reply->errorString();
            }
            reply->deleteLater();
    });
}

void Widget::uploadVideo(const QString &filePath, const QString &serverIp, int port)
{
    // 1. 创建文件对象
            QFile *file = new QFile(filePath);
            if (!file->open(QIODevice::ReadOnly)) {
                qDebug() << "无法打开文件:" << filePath;
                delete file;
                return;
            }

            // 2. 创建多部分表单数据
            QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);

            // 3. 创建文件部分 (字段名必须与后端一致)
            QHttpPart videoPart;
            videoPart.setHeader(QNetworkRequest::ContentDispositionHeader,
                               QVariant("form-data; name=\"video\"; filename=\"" + QFileInfo(filePath).fileName() + "\""));
            videoPart.setBodyDevice(file);
            file->setParent(multiPart); // 确保文件由 multiPart 管理

            // 4. 添加文件部分到表单
            multiPart->append(videoPart);

            // 5. 创建请求
            QUrl url(QString("http://%1:%2/upload").arg(serverIp).arg(port));
            QNetworkRequest request(url);

            // 6. 发送POST请求
            QNetworkReply *reply = networkManager->post(request, multiPart);
            multiPart->setParent(reply); // 由 reply 管理内存

            // 7. 连接信号槽处理响应
            connect(reply, &QNetworkReply::finished, this, [this, reply, file, multiPart]() {
                if (reply->error() == QNetworkReply::NoError) {
                    // 成功响应
                    QByteArray response = reply->readAll();
                    qDebug() << "上传成功，响应：" << response;

                    // 解析 JSON 获取视频 URL（兼容 Qt 5.9 及更低版本）
                    QJsonDocument doc = QJsonDocument::fromJson(response);
                    if (!doc.isEmpty() && doc.isObject()) {
                        QJsonObject obj = doc.object();
                        if (obj.contains("videoUrl")) {
                            QString videoUrl = obj["videoUrl"].toString();
                            qDebug() << "video url:" << videoUrl;
                        } else {
                            qDebug() << "no video url in response";
                        }
                    } else {
                        qDebug() << "analyse json fail";
                    }
                } else {
                    // 错误处理
                    qDebug() << "upload fail:" << reply->errorString();
                }

                // 清理资源
                reply->deleteLater();
                file->deleteLater();
                multiPart->deleteLater();
            });
}


void Widget::on_pushButton_3_clicked()
{
    if(ui->pushButton_3->isChecked())
    {
        ui->pushButton_3->setText("关闭");
        ui->humidifierstatus->setText("开启");
        ui->humidifierstatus->setStyleSheet("color: rgb(0, 255, 127);");
        serialPort->write("humidifier:true");
    }
    else
    {
        ui->pushButton_3->setText("开启");
        ui->humidifierstatus->setText("关闭");
        ui->humidifierstatus->setStyleSheet("color: rgb(255, 0, 0);");
        serialPort->write("humidifier:falsee");
    }
}

void Widget::updateVideoIcon(const QString &videoPath,const QString &storagePath)
{
    if(my_player->i < my_player->videoCount)
    {
        videoTable[storageIndex][my_player->i] = videoPath;
        thumbnailTable[storageIndex][my_player->i] = storagePath;
        my_player->i++;
        if(my_player->i % 6 == 0)
        {
            storageIndex++;
        }
    }
}

void Widget::on_pushButton_4_clicked()
{
    // 使用 QPointer 管理窗口指针，防止悬空
    QPointer<QDialog> videoDialog = new QDialog(this);
    videoDialog->setAttribute(Qt::WA_DeleteOnClose); // 窗口关闭时自动删除
    videoDialog->resize(1920, 1080); // 设置默认大小

    // 创建视频显示控件
    QVideoWidget *videoWidget = new QVideoWidget(videoDialog);
    videoWidget->resize(videoDialog->size());

    // 设置视频输出到新窗口
    pPlayer->setVideoOutput(videoWidget);

    // 连接媒体状态变化信号，判断是否播放结束
    connect(pPlayer, &QMediaPlayer::mediaStatusChanged, this, [videoDialog](QMediaPlayer::MediaStatus status) {
        if (status == QMediaPlayer::EndOfMedia && videoDialog) {
            videoDialog->close(); // 视频播放结束，关闭窗口
        }
    });

    QUrl file = QUrl::fromLocalFile(this->videoPath[0]);
    qDebug() << file <<endl;
    pPlayer->setMedia(file); // 直接设置媒体，跳过播放列表

    // 显示窗口
    videoDialog->show();

    // 开始播放
    pPlayer->play();
}

void Widget::on_pushButton_5_clicked()
{
    // 使用 QPointer 管理窗口指针，防止悬空
    QPointer<QDialog> videoDialog = new QDialog(this);
    videoDialog->setAttribute(Qt::WA_DeleteOnClose); // 窗口关闭时自动删除
    videoDialog->resize(1600, 1000); // 设置默认大小

    // 创建视频显示控件
    QVideoWidget *videoWidget = new QVideoWidget(videoDialog);
    videoWidget->resize(videoDialog->size());

    // 设置视频输出到新窗口
    pPlayer->setVideoOutput(videoWidget);

    // 连接媒体状态变化信号，判断是否播放结束
    connect(pPlayer, &QMediaPlayer::mediaStatusChanged, this, [videoDialog](QMediaPlayer::MediaStatus status) {
        if (status == QMediaPlayer::EndOfMedia && videoDialog) {
            videoDialog->close(); // 视频播放结束，关闭窗口
        }
    });

    QUrl file = QUrl::fromLocalFile(this->videoPath[1]);
    qDebug() << file <<endl;
    pPlayer->setMedia(file); // 直接设置媒体，跳过播放列表

    // 显示窗口
    videoDialog->show();

    // 开始播放
    pPlayer->play();
}

void Widget::on_pushButton_6_clicked()
{
    // 使用 QPointer 管理窗口指针，防止悬空
    QPointer<QDialog> videoDialog = new QDialog(this);
    videoDialog->setAttribute(Qt::WA_DeleteOnClose); // 窗口关闭时自动删除
    videoDialog->resize(1600, 1000); // 设置默认大小

    // 创建视频显示控件
    QVideoWidget *videoWidget = new QVideoWidget(videoDialog);
    videoWidget->resize(videoDialog->size());

    // 设置视频输出到新窗口
    pPlayer->setVideoOutput(videoWidget);

    // 连接媒体状态变化信号，判断是否播放结束
    connect(pPlayer, &QMediaPlayer::mediaStatusChanged, this, [videoDialog](QMediaPlayer::MediaStatus status) {
        if (status == QMediaPlayer::EndOfMedia && videoDialog) {
            videoDialog->close(); // 视频播放结束，关闭窗口
        }
    });

    QUrl file = QUrl::fromLocalFile(this->videoPath[2]);
    qDebug() << file <<endl;
    pPlayer->setMedia(file); // 直接设置媒体，跳过播放列表

    // 显示窗口
    videoDialog->show();

    // 开始播放
    pPlayer->play();
}

void Widget::on_pushButton_7_clicked()
{
    // 使用 QPointer 管理窗口指针，防止悬空
    QPointer<QDialog> videoDialog = new QDialog(this);
    videoDialog->setAttribute(Qt::WA_DeleteOnClose); // 窗口关闭时自动删除
    videoDialog->resize(1600, 1000); // 设置默认大小

    // 创建视频显示控件
    QVideoWidget *videoWidget = new QVideoWidget(videoDialog);
    videoWidget->resize(videoDialog->size());

    // 设置视频输出到新窗口
    pPlayer->setVideoOutput(videoWidget);

    // 连接媒体状态变化信号，判断是否播放结束
    connect(pPlayer, &QMediaPlayer::mediaStatusChanged, this, [videoDialog](QMediaPlayer::MediaStatus status) {
        if (status == QMediaPlayer::EndOfMedia && videoDialog) {
            videoDialog->close(); // 视频播放结束，关闭窗口
        }
    });

    QUrl file = QUrl::fromLocalFile(this->videoPath[3]);
    qDebug() << file <<endl;
    pPlayer->setMedia(file); // 直接设置媒体，跳过播放列表

    // 显示窗口
    videoDialog->show();

    // 开始播放
    pPlayer->play();
}

void Widget::on_pushButton_8_clicked()
{
    // 使用 QPointer 管理窗口指针，防止悬空
    QPointer<QDialog> videoDialog = new QDialog(this);
    videoDialog->setAttribute(Qt::WA_DeleteOnClose); // 窗口关闭时自动删除
    videoDialog->resize(1600, 1000); // 设置默认大小

    // 创建视频显示控件
    QVideoWidget *videoWidget = new QVideoWidget(videoDialog);
    videoWidget->resize(videoDialog->size());

    // 设置视频输出到新窗口
    pPlayer->setVideoOutput(videoWidget);

    // 连接媒体状态变化信号，判断是否播放结束
    connect(pPlayer, &QMediaPlayer::mediaStatusChanged, this, [videoDialog](QMediaPlayer::MediaStatus status) {
        if (status == QMediaPlayer::EndOfMedia && videoDialog) {
            videoDialog->close(); // 视频播放结束，关闭窗口
        }
    });

    QUrl file = QUrl::fromLocalFile(this->videoPath[4]);
    qDebug() << file <<endl;
    pPlayer->setMedia(file); // 直接设置媒体，跳过播放列表

    // 显示窗口
    videoDialog->show();

    // 开始播放
    pPlayer->play();
}

void Widget::on_pushButton_9_clicked()
{
    // 使用 QPointer 管理窗口指针，防止悬空
    QPointer<QDialog> videoDialog = new QDialog(this);
    videoDialog->setAttribute(Qt::WA_DeleteOnClose); // 窗口关闭时自动删除
    videoDialog->resize(1600, 1000); // 设置默认大小

    // 创建视频显示控件
    QVideoWidget *videoWidget = new QVideoWidget(videoDialog);
    videoWidget->resize(videoDialog->size());

    // 设置视频输出到新窗口
    pPlayer->setVideoOutput(videoWidget);

    // 连接媒体状态变化信号，判断是否播放结束
    connect(pPlayer, &QMediaPlayer::mediaStatusChanged, this, [videoDialog](QMediaPlayer::MediaStatus status) {
        if (status == QMediaPlayer::EndOfMedia && videoDialog) {
            videoDialog->close(); // 视频播放结束，关闭窗口
        }
    });

    QUrl file = QUrl::fromLocalFile(this->videoPath[5]);
    qDebug() << file <<endl;
    pPlayer->setMedia(file); // 直接设置媒体，跳过播放列表

    // 显示窗口
    videoDialog->show();

    // 开始播放
    pPlayer->play();
}

void Widget::on_pushButton_10_clicked()
{
    m_stackedLayout->setCurrentIndex(0);
}

//开始录制视频
void Widget::on_pushButton_12_clicked()
{
    m_stackedLayout->setCurrentIndex(3);

    // 防止重复启动 ✅
    if (videoProcess->state() == QProcess::Running ||
        audioProcess->state() == QProcess::Running) {
        QMessageBox::warning(this, "警告", "录制已在进行中，请先停止");
        return;
    }

    // 清理旧文件
    QFile::remove(videoFile);
    QFile::remove(audioFile);
    //QFile::remove(outputFile);

    // 启动视频录制 ✅
    QStringList videoArgs;
    videoArgs << "v4l2src" << "device=/dev/video0"
              << "!" << "video/x-raw,width=1920,height=1080,framerate=30/1"
              << "!" << "tee" << "name=t"
              << "t." << "!" << "queue" << "!" << "videoconvert" << "!" << "mpph264enc"
              << "!" << "h264parse" << "config-interval=-1"
              << "!" << "mpegtsmux"
              << "!" << "filesink" << "location=" + videoFile
              << "t." << "!" << "queue" << "!" << "videoconvert" << "!" << "autovideosink";

    videoProcess->start("gst-launch-1.0", videoArgs);
    if (!videoProcess->waitForStarted()) {
        QMessageBox::critical(this, "错误", "视频录制启动失败: " + videoProcess->errorString());
        return;
    }

    // 启动音频录制 ✅
    QStringList audioArgs;
    audioArgs << "-c" << "2"
              << "-r" << "44100"
              << "-f" << "S16_LE"
              << audioFile;

    audioProcess->start("arecord", audioArgs);
    if (!audioProcess->waitForStarted()) {
        QMessageBox::critical(this, "错误", "音频录制启动失败: " + audioProcess->errorString());
        videoProcess->kill();
        return;
    }

    QTimer::singleShot(2000, this, [this]() {
        // 强制恢复焦点
        this->activateWindow();          // 激活主窗口
        this->setFocus();                // 设置焦点
        ui->pushButton_11->setFocus();         // 如果你想让焦点回到按钮上
        this->resize(QSize(500,250));
    });
}

//结束录制视频
void Widget::on_pushButton_11_clicked()
{
    // 终止录制进程 ✅
    if (videoProcess->state() == QProcess::Running) {
        videoProcess->terminate();
        if (!videoProcess->waitForFinished(3000)) {
            videoProcess->kill();  // 强制终止
        }
    }
    if (audioProcess->state() == QProcess::Running) {
        audioProcess->terminate();
        if (!audioProcess->waitForFinished(3000)) {
            audioProcess->kill();
        }
    }

    mergeAudioVideo();
}

void Widget::on_prevPage_clicked()
{
    if(pageIndex == 0)//如果在第1页就不能切上一页
    {

    }
    else
    {
        pageIndex--;
        showPageIcon(pageIndex);
    }
}

void Widget::on_nextPage_clicked()
{
    if(pageIndex == 3)//如果在第4页就不能切下一页
    {

    }
    else
    {
        pageIndex++;
        showPageIcon(pageIndex);
    }
}

void Widget::on_pushButton_13_clicked()
{
    if(ui->pushButton_13->isChecked())
    {
        ui->pushButton_13->setText("关闭");
        ui->lightStatus->setText("开启");
        ui->lightStatus->setStyleSheet("color: rgb(0, 255, 127);");
        serialPort->write("light:true");
    }
    else
    {
        ui->pushButton_13->setText("开启");
        ui->lightStatus->setText("关闭");
        ui->lightStatus->setStyleSheet("color: rgb(255, 0, 0);");
        serialPort->write("light:falsee");
    }
}

void Widget::uploadSensorData()
{
    // 添加时间校正（示例：假设设备时区为UTC+8）
    QDateTime currentLocalTime = QDateTime::currentDateTime();
    QString formattedTime = currentLocalTime.toString("yyyy-MM-dd HH:mm:ss");
    // 构建传感器数据
    QJsonObject data;
    data["temperature"] = ui->label_4->text().toInt();
    data["humidity"] = ui->label_14->text().left(ui->label_14->text().indexOf("%")).toInt();
    if(ui->label_38->text() == "有人")
    {
        data["presence"] = 1;
    }
    else
    {
        data["presence"] = 0;
    }
    data["movement"] = ui->label_19->text().toInt();
    data["breathing"] = ui->label_20->text().toInt();
    data["heart_rate"] = ui->label_32->text().toInt();
    data["smoke_level"] = ui->label_23->text();
    data["humidifier_status"] = ui->humidifierstatus->text(); // 当前状态（可扩展为动态获取）
    data["light_status"] = ui->lightStatus->text();
    //data["timestamp"] = formattedTime; // 强制使用正确时间
    // 在 uploadSensorData 函数中添加调试输出
    qDebug() << "上传时间戳:" << formattedTime << endl; // 验证时间格式

    // 发送 POST 请求
    QNetworkRequest request;
    request.setUrl(QUrl("http://47.109.75.129:3000/api/sensor/data"));
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");

    QNetworkReply *reply = networkManager->post(request, QJsonDocument(data).toJson());
    connect(reply, &QNetworkReply::finished, this, [this, reply]() {
        handleUploadFinished(reply);
    });
}

void Widget::pollControlCommands()
{
    // 发起轮询请求
    QNetworkRequest request;
    request.setUrl(QUrl("http://47.109.75.129:3000/api/control/poll"));

    QNetworkReply *reply = networkManager->get(request);
    connect(reply, &QNetworkReply::finished, this, [this, reply]() {
        handlePollFinished(reply);
    });
}

void Widget::handleUploadFinished(QNetworkReply *reply)
{
    if (reply->error() == QNetworkReply::NoError) {
        qDebug() << "sensor data update succ";
    } else {
        qDebug() << "upload fail:" << reply->errorString();
    }
    reply->deleteLater();
}

void Widget::handlePollFinished(QNetworkReply *reply)
{
    if (reply->error() == QNetworkReply::NoError) {
        QJsonDocument doc = QJsonDocument::fromJson(reply->readAll());
        if (!doc.isNull() && doc.isObject()) {
            QJsonObject command = doc.object();
            QString device = command["device"].toString();
            QString action = command["action"].toString();
            int commandId = command["id"].toInt();
            qDebug() << "get commad - device:" << device << "action:" << action;

            // ✅ 执行指令并更新本地状态
            if (device == "humidifier") {
                setHumidifier(action == "on");
                uploadSensorData();
            } else if (device == "light") {
                setLight(action == "on");
                uploadSensorData();
            }

            // ✅ 标记指令为已处理
            QNetworkRequest markRequest;
            markRequest.setUrl(QUrl(QString("http://47.109.75.129:3000/api/control/%1").arg(commandId)));
            markRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
            networkManager->put(markRequest, QByteArray());
        }
    }
    reply->deleteLater();
}

void Widget::sendManualAlarm(const QString &message)
{
    QUrl url("http://47.109.75.129:3000/trigger-alarm");
    QNetworkRequest request(url);
    request.setHeader(QNetworkRequest::ContentTypeHeader,
                     "application/json");

    QJsonObject json;
    json["message"] = message;
    QJsonDocument doc(json);

    // 发送POST请求
    QNetworkReply *reply = networkManager->post(request, doc.toJson());
    connect(reply, &QNetworkReply::finished, [this, reply]() {
        handleAlarmResponse(reply); // 自定义带参数的槽
    });

    connect(reply, &QNetworkReply::sslErrors, [this, reply](const QList<QSslError> &errors) {
        handleAlarmError(reply, errors); // 自定义带参数的槽
    });
}

void Widget::handleAlarmError(QNetworkReply* reply, const QList<QSslError> &errors)
{
    Q_UNUSED(errors);
    qDebug() << "net error" << endl;
    emit alarmSentFailed("erorr connect net");
    QMessageBox::warning(this, "net error", "can not connect server");
    reply->deleteLater();
}

void Widget::handleAlarmResponse(QNetworkReply *reply)
{
    if (reply->error() == QNetworkReply::NoError) {
            qDebug() << "ergency send succ";
            emit alarmSentSuccess();
            //QMessageBox::information(this, "成功", "报警已发送");
        } else {
            qDebug() << "ergency send fail:" << reply->errorString();
            emit alarmSentFailed(reply->errorString());
            //QMessageBox::critical(this, "错误",
                                 //"发送报警失败: " + reply->errorString());
        }
        reply->deleteLater();
}

void Widget::setHumidifier(bool on)
{
    qDebug() << "humdifer status update:" << (on ? "开启" : "关闭");
    // TODO: 这里添加实际硬件控制逻辑
    ui->pushButton_3->animateClick();
}

void Widget::setLight(bool on)
{
    qDebug() << "light status update:" << (on ? "开启" : "关闭");
    // TODO: 这里添加实际硬件控制逻辑
    ui->pushButton_13->animateClick();
}

void Widget::on_pushButton_15_clicked()
{
    qDebug() << "alarm send" << endl;
    sendManualAlarm("患者发出报警信息");
}
